#pragma once
#include "qbprotocol/include/simple_encoder.h"
#include <vector>
#include <map>
/*
	[内存优化][scofined.qi]
	要解决的问题:
	该类尝试解决这样一种场景的内存占用开销,同时保持性能不下降的过分厉害:
	以字符串为主键,来管理一堆尺寸较为庞大的C++结构体对象

	解决思路:
	放进去的时候,将结构体编码压缩成内存紧凑的内置对象
	读取的时候,将内置对象解码成原先的结构体
	也可以:读取的时候,可以采取特殊的方式,来快速获取原先结构体的成员

	现存事实:
	CBondCompanyRep中,以较短字符串(brokerID)作为主键,存储REPORT
	REPORT结构体较大,通过字段成员来使用,且使用广泛,重构成本极大
	统计数据表明,REPORT中绝大多数成员是默认值

	编码结构:
	头部+每个字段的实际内容偏移量+每个字段的实际编码内容
	如果该字段是默认空值,那么不对其内容做编码,直接跳过
	统计数据表明,可以达到29%的压缩率
	
	其他优化:
	1.KeyString针对短字符串做编码优化,4个字节可以原地表示长度<=3的字符串
	相对之前,std::string则需要24个字节
	2.针对只有少量几个键值对,map对于vector并无性能优势
	  考虑到缓存友好vector性能更快,内存占用更少
	  因此CBondCompanyRep中使用EncodeBufInfoVector来存储
*/
enum kObjectMetaId{
	kObjectMetaIdReport=1,
	kObjectMetaIdIssuer = 2,
};
class TableEncoder{
public:
	char* Encode(const char* data, int size,int metaId, int& length)
	{
		return qb::base::SimpleEncoder::Get().Encode(data, size, metaId, length);
	}
	int Decode(const void* encodedData, int encodedSize, char* rawData, int capcity)
	{
		return qb::base::SimpleEncoder::Get().Decode(encodedData, encodedSize, rawData, capcity);
	}
};
class ReportEncoder{
public:
	typedef unsigned short ushort;
	enum kType{
		kTypeChar,
		kTypeTime,
		kTypeInt,
		kTypeInt64,
		kTypeDouble,
		kTypeString,
		kTypeCount,
	};
	struct FieldInfo{
		kType	type;	// 字段的类型
		int		pos;	// 字段的偏移量
		int		len;	// 是字段的长度
	};
	class FieldOffset{
	public:
		std::vector<FieldInfo>	m_fields;
		int Add(const char* name, kType type, int pos, int len)
		{
			m_fields.emplace_back(FieldInfo{ type, pos, len });
			return m_fields.size() - 1;
		}
	};
	class FieldArray{
	public:
		struct Offset{
			ushort	type : 3;	// 原始字段的数据类型
			ushort	dft : 1;	// 如果为1,表示是默认值,不需要编码进去
			ushort	pos : 12;	// 表示编码后的位置,长度不用指定,后续一个pos会计算出来
		public:
			Offset(ushort t, ushort d, ushort p) :type(t), dft(d), pos(p){}
		};
	protected:
		ushort		m_count;		// 总字段个数
		ushort		m_bytes;		// 总字节大小
		Offset		m_offsets[1];	// 编码位置数组
	public:
		int GetBytes()const{ return m_bytes; }
		int GetFieldCount()const{ return m_count; }
		inline const void* GetField(int index)const{
			static const char dft_value[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
			if (m_offsets[index].dft){
				return dft_value;
			}
			return ((const char*)this) + m_offsets[index].pos;
		}
		inline static bool IsDefault(const char* ptr, int size)
		{
			for (int i = 0; i < size; i++)
			{
				if (ptr[i] != 0)
					return false;
			}
			return true;
		}
		static FieldArray* Create(const char* src, const FieldOffset& fields);
		static void Destroy(FieldArray* farray);
		static bool Decode(const FieldArray* farray, char* dest, const FieldOffset& fields);
	};
protected:
	class MetaInit{
	public:
		FieldOffset	m_offsets;
		MetaInit(){
			InitReport(&m_offsets);
		}
		void InitReport(FieldOffset* meta);

	};
	static FieldOffset& GetOffsets(){
		static MetaInit meta;
		return meta.m_offsets;
	}
public:
	static char* Encode(const char* data, int size, int metaId, int& length);
	static int Decode(const void* encodedData, int encodedSize, char* rawData, int capcity);
};
struct EncodeBufInfo{
	char*		buf;	// 编码后的数据
	int			size;	// 编码后的长度
};
struct KeyValue{
	qb::base::TinyString	first;
	EncodeBufInfo		second;
};
/*
	可以选用两种容器,CCompanyRepMap中,brokerID个数很少,因此
	选用EncodeBufInfoVector
*/
typedef std::map<qb::base::TinyString, EncodeBufInfo> EncodeBufInfoMap;
typedef std::vector<KeyValue> EncodeBufInfoVector;
template<typename OBJECT, typename ENCODER, int META_ID,
	typename Container = EncodeBufInfoMap>
class ZippedObjectMap{
public:

	struct ResultPair{
		qb::base::TinyString	first;
		OBJECT		second;
	};
	//typedef std::map<KeyString, EncodeBufInfo> Container;
	//typedef std::vector<KeyValue> Container;
	typedef typename Container::iterator mapiterator;
	typedef typename Container::const_iterator mapciterator;
	using key_type = qb::base::TinyString;
	using mapped_type = OBJECT;
public:
	Container	m_keyvalues;
	ZippedObjectMap(const ZippedObjectMap&) = delete;
public:
	ZippedObjectMap(){}
	~ZippedObjectMap(){ clear(); }
	class iterator{
		mapiterator			m_itor;
        ZippedObjectMap*	m_owner;     
		ResultPair*			m_result;	// 指向栈上变量的指针
	public:
		iterator(ZippedObjectMap* own, const mapiterator& mit, ResultPair* result) :
			m_owner(own), m_itor(mit), m_result(result)
		{
			if (m_owner && m_result)
				m_owner->decode(mit, m_result);
		}
		iterator(const iterator& it) :m_itor(it.m_itor), m_owner(it.m_owner), m_result(it.m_result){}
		ResultPair* operator->(){
			//BASSERT(m_result);
			//BASSERT(m_itor != m_owner->end().m_itor);
			return m_result;
		}
		bool operator!=(const iterator& it)const{
			return m_itor != it.m_itor;
		}
		iterator operator++(){
			return iterator(m_owner, ++m_itor, m_result);
		}
		iterator operator++(int){
			return iterator(m_owner, ++m_itor, m_result);
		}
		operator mapiterator(){ return m_itor; }
	};
	class wrapper{
        ZippedObjectMap&	m_container;
		ResultPair			m_result;
	public:
        wrapper(ZippedObjectMap& cont) :m_container(cont){}
        inline iterator begin(){ return m_container.begin(&m_result); }
        inline iterator end(){ return m_container.end(); }
        inline iterator find(const key_type& key){ return m_container.find(key, &m_result); }
        inline int size()const{ return m_container.size(); }
		inline int bytes()const{ return 0; }
        inline void clear(){ m_container.clear(); }
        inline void emplace(const key_type& key, const mapped_type& rpt){
            m_container.emplace(key, rpt);
		}
        inline iterator erase(iterator _Where){ return m_container.erase(_Where, &m_result); }
	};

	
	EncodeBufInfo find(const key_type& key){
		auto it= findImpl<Container>(key);
		if (it == m_keyvalues.end())return EncodeBufInfo{ nullptr, 0 };
		return it->second;
	}
	int getall(EncodeBufInfo* infos, int capcity)const
	{
		if ((int)m_keyvalues.size() > capcity)
			return -1;
		int i = 0;
		for (auto it = m_keyvalues.begin(); it != m_keyvalues.end(); ++it)
			infos[i++] = it->second;
		return m_keyvalues.size();
	}
protected://适配两个容器的模板
#ifdef WIN32
	template<typename CONT>
	mapiterator findImpl(const key_type& key){
		return m_keyvalues.find(key);
    }
    template<>
    mapiterator findImpl<std::vector<KeyValue>>(const key_type& key){
        for (auto it = m_keyvalues.begin(); it != m_keyvalues.end(); ++it)
        {
            if (it->first == key)
                return it;
        }
        return m_keyvalues.end();
    }

    template<typename CONT>
    void emplaceImpl(const key_type& key, const EncodeBufInfo& info){
        m_keyvalues.emplace(Container::value_type{ key, info });
    }
    template<>
    void emplaceImpl<std::vector<KeyValue>>(const key_type& key, const EncodeBufInfo& info){
        //针对vector,覆盖掉vector自身的扩容机制,总是扩充1个,确保没有浪费多余的内存
        if (m_keyvalues.size() >= m_keyvalues.capacity())
            m_keyvalues.reserve(m_keyvalues.capacity() + 1);
        m_keyvalues.emplace_back(Container::value_type{ key, info });
    }
#else
    template<typename CONT>
    mapiterator findImpl(const key_type& key){
        for (auto it = m_keyvalues.begin(); it != m_keyvalues.end(); ++it)
        {
            if (it->first == key)
                return it;
        }
        return m_keyvalues.end();
    }

    template<typename CONT>
    void emplaceImpl(const key_type& key, const EncodeBufInfo& info){
        //针对vector,覆盖掉vector自身的扩容机制,总是扩充1个,确保没有浪费多余的内存
        if (m_keyvalues.size() >= m_keyvalues.capacity())
            m_keyvalues.reserve(m_keyvalues.capacity() + 1);
        m_keyvalues.emplace_back(typename Container::value_type{key, info});
    }
#endif
public:
	iterator begin(ResultPair* result){ return{ this, m_keyvalues.begin(), result }; }
	iterator end(){ return{ this, m_keyvalues.end(), nullptr }; }
    iterator find(const key_type& key, ResultPair* result){
        return{ this, findImpl<Container>(key), result };
	}
	int size()const{ return m_keyvalues.size(); }
	void clear()
	{
		for (auto it = m_keyvalues.begin(); it != m_keyvalues.end(); ++it)
		{
			qb::base::EncodeBuf::Free(it->second.buf);
		}
		m_keyvalues.clear();
	}
    iterator erase(iterator _Where, ResultPair* result)
	{
        auto it = m_keyvalues.erase((mapiterator)_Where);
        return iterator(this, it, result);
	}
    void emplace(const key_type& key, const OBJECT& rpt)
	{
        auto it = findImpl<Container>(key);
		if (it != m_keyvalues.end())
		{
			const EncodeBufInfo& info = it->second;
			qb::base::EncodeBuf::Free(info.buf);
			m_keyvalues.erase(it);
        }
        int length = 0;
		char* buf = ENCODER::Encode((const char*)&rpt, sizeof(rpt), META_ID, length);
        emplaceImpl<Container>(key, EncodeBufInfo{ buf, length });
	}

	void decode(const mapiterator& mit, ResultPair* result)
	{
		// 将迭代器mit指向的数据解码到result中
		if (mit != m_keyvalues.end() && result)
		{
			result->first = mit->first;
			const EncodeBufInfo& info = mit->second;
			ENCODER::Decode((const void*)info.buf, info.size, (char*)&(result->second), sizeof(OBJECT));
		}
	}
};
